/*
 * Copyright 2015 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.channel;

import static io.netty.util.internal.ObjectUtil.checkPositive;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.UncheckedBooleanSupplier;

public abstract class DefaultMaxMessagesRecvByteBufAllocator implements MaxMessagesRecvByteBufAllocator {
    //每次循环最多能读取的消息数量
    private volatile int maxMessagesPerRead;
    //默认为true
    private volatile boolean respectMaybeMoreData = true;

    public DefaultMaxMessagesRecvByteBufAllocator() {
        this(1);
    }

    public DefaultMaxMessagesRecvByteBufAllocator(int maxMessagesPerRead) {
        maxMessagesPerRead(maxMessagesPerRead);
    }

    @Override
    public int maxMessagesPerRead() {
        return maxMessagesPerRead;
    }

    @Override
    public MaxMessagesRecvByteBufAllocator maxMessagesPerRead(int maxMessagesPerRead) {
        checkPositive(maxMessagesPerRead, "maxMessagesPerRead");
        this.maxMessagesPerRead = maxMessagesPerRead;
        return this;
    }

    public DefaultMaxMessagesRecvByteBufAllocator respectMaybeMoreData(boolean respectMaybeMoreData) {
        this.respectMaybeMoreData = respectMaybeMoreData;
        return this;
    }

    public final boolean respectMaybeMoreData() {
        return respectMaybeMoreData;
    }

    public abstract class MaxMessageHandle implements ExtendedHandle {
        //channel Config对象
        private ChannelConfig config;
        //每次读循环最多能读取的消息数量
        private int maxMessagePerRead;
        //已读消息数
        private int totalMessages;
        //已读消息的大小
        private int totalBytesRead;
        //预测下次读取的字节数
        private int attemptedBytesRead;
        //最后一次读取的字节数
        private int lastBytesRead;
        //默认是true
        private final boolean respectMaybeMoreData = DefaultMaxMessagesRecvByteBufAllocator.this.respectMaybeMoreData;
        //预估读取量 == 最后一次读取量
        private final UncheckedBooleanSupplier defaultMaybeMoreSupplier = new UncheckedBooleanSupplier() {
            @Override
            public boolean get() {
                return attemptedBytesRead == lastBytesRead;
            }
        };
        //重置当前的Handle
        @Override
        public void reset(ChannelConfig config) {
            this.config = config;
            //默认情况下是16。
            maxMessagePerRead = maxMessagesPerRead();
            totalMessages = totalBytesRead = 0;
        }
        //分配内存的方法，但是真正分配内存的并不是当前的类
        //而是ByteBufAllocator
        //guess方法提供要分配的内存大小
        @Override
        public ByteBuf allocate(ByteBufAllocator alloc) {
            return alloc.ioBuffer(guess());
        }

        @Override
        public final void incMessagesRead(int amt) {
            totalMessages += amt;
        }

        @Override
        public void lastBytesRead(int bytes) {
            lastBytesRead = bytes;
            if (bytes > 0) {
                totalBytesRead += bytes;
            }
        }

        @Override
        public final int lastBytesRead() {
            return lastBytesRead;
        }

        @Override
        public boolean continueReading() {
            return continueReading(defaultMaybeMoreSupplier);
        }
        //这个方法是控制消息处理读取过程中的循环结束条件
        //什么时候返回成功？
        //config.isAutoRead() 默认是true
        //respectMaybeMoreData默认是true，所以取反就是false
        //maybeMoreDataSupplier.get() 返回true表示最后一次读取的数量和评估的数据量一直，说明此时缓冲区可能还是有数据没有读取完
        //返回false说明数据读取完了或者channel关闭了
        //totalMessages < maxMessagePerRead 成立说明：一次unsafe.read操作最多只能从channel读取16次数据，不能超过。
        //totalBytesRead > 0
        //客户端正常情况下都是true，什么时候<=0?读物的数据量太大了，超过了int的最大值，导致这个变量溢出。
        //服务端并没有代码来控制这个变量，所以会是false，也就是说，服务端其实每次执行unsafe.read 里面的do...while...循环只会执行一次。
        @Override
        public boolean continueReading(UncheckedBooleanSupplier maybeMoreDataSupplier) {
            return config.isAutoRead() &&
                   (!respectMaybeMoreData || maybeMoreDataSupplier.get()) &&
                   totalMessages < maxMessagePerRead &&
                   totalBytesRead > 0;
        }

        @Override
        public void readComplete() {
        }

        @Override
        public int attemptedBytesRead() {
            return attemptedBytesRead;
        }

        @Override
        public void attemptedBytesRead(int bytes) {
            attemptedBytesRead = bytes;
        }

        protected final int totalBytesRead() {
            return totalBytesRead < 0 ? Integer.MAX_VALUE : totalBytesRead;
        }
    }
}
